package example.demo.unsafe;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;

/**
 * 实现CAS-lock
 */
public class UseUnsafeImplCASLock {
    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe;
    private static final long valueOffset;

    static {
        try {
            Class<Unsafe> unsafeClass = Unsafe.class;
            Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            //类变量,所以不需要对象实例
            unsafe = (Unsafe) theUnsafe.get(null);
            valueOffset = unsafe.objectFieldOffset
                    (UseUnsafeImplCASLock.class.getDeclaredField("value"));
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    private volatile int value;

    public void lock() {
        int tryCount = 1;
        while (!unsafe.compareAndSwapInt(this, valueOffset, 0, 1)) {
            if (((tryCount++) & 31) == 0) {
                Thread.yield();
                tryCount = 1;
            }
        }
    }

    public void unlock() {
        value = 0;
    }

    static int sum = 0;
    static int count = 500;
    static CountDownLatch latch = new CountDownLatch(count);
    static CountDownLatch main = new CountDownLatch(count);

    public static void main(String[] args) throws InterruptedException {
        UseUnsafeImplCASLock casLock = new UseUnsafeImplCASLock();
        for (int i = 0; i < count; i++) {
            new Thread(() -> {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //锁这里就行了
                casLock.lock();
                for (int j = 0; j < 100000; j++) {
//                    casLock.lock();//放在for里面不是很好。。。
                    sum++;
//                    casLock.lock();
                }
                casLock.unlock();
                main.countDown();
            }).start();
            latch.countDown();
        }
        main.await();
        System.out.println(sum);
    }
}
